/* tslint:disable */

import { ApolloError } from 'apollo-client'
import { GraphQLError } from 'graphql'

export enum PropheticErrorCode {
  CodeLessError = 'NONE',
  ErrPuzzle404 = '1003',
  ErrRoom404 = '1001',
  InternalError = '2',
  ErrNotHost = '3002',
  ErrObjName404 = '1005',
  ErrNotLogin = '3003',
  NotFoundError = '1',
  ErrNoToken = '3001',
  ErrPlayer404 = '1002',
  ErrPlayerState404 = '1006',
  OK = '0',
  ErrCharacterData404 = '1004',
  ErrInvalidToken = '3004',
  AuthError = '3'
}

export class PropheticError {
  constructor(public codes: string[]) {}

  private inCodes(code: PropheticErrorCode) {
    return this.codes.indexOf(code) > -1
  }

  get isCodeLessError() {
    return this.inCodes(PropheticErrorCode.CodeLessError)
  }
  get isErrPuzzle404() {
    return this.inCodes(PropheticErrorCode.ErrPuzzle404)
  }
  get isErrRoom404() {
    return this.inCodes(PropheticErrorCode.ErrRoom404)
  }
  get isInternalError() {
    return this.inCodes(PropheticErrorCode.InternalError)
  }
  get isErrNotHost() {
    return this.inCodes(PropheticErrorCode.ErrNotHost)
  }
  get isErrObjName404() {
    return this.inCodes(PropheticErrorCode.ErrObjName404)
  }
  get isErrNotLogin() {
    return this.inCodes(PropheticErrorCode.ErrNotLogin)
  }
  get isNotFoundError() {
    return this.inCodes(PropheticErrorCode.NotFoundError)
  }
  get isErrNoToken() {
    return this.inCodes(PropheticErrorCode.ErrNoToken)
  }
  get isErrPlayer404() {
    return this.inCodes(PropheticErrorCode.ErrPlayer404)
  }
  get isErrPlayerState404() {
    return this.inCodes(PropheticErrorCode.ErrPlayerState404)
  }
  get isOK() {
    return this.inCodes(PropheticErrorCode.OK)
  }
  get isErrCharacterData404() {
    return this.inCodes(PropheticErrorCode.ErrCharacterData404)
  }
  get isErrInvalidToken() {
    return this.inCodes(PropheticErrorCode.ErrInvalidToken)
  }
  get isAuthError() {
    return this.inCodes(PropheticErrorCode.AuthError)
  }
}

export interface Handler {
  (): any
}

export class PropheticErrorHandled {
  private handler: Handler = () => {}

  constructor(public codes: string[]) {}

  private inCodes(code: PropheticErrorCode, handler: Handler) {
    if (this.codes.indexOf(code) > -1) {
      this.handler = handler
    }

    return this
  }

  CodeLessError(handler: Handler) {
    return this.inCodes(PropheticErrorCode.CodeLessError, handler)
  }
  ErrPuzzle404(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrPuzzle404, handler)
  }
  ErrRoom404(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrRoom404, handler)
  }
  InternalError(handler: Handler) {
    return this.inCodes(PropheticErrorCode.InternalError, handler)
  }
  ErrNotHost(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrNotHost, handler)
  }
  ErrObjName404(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrObjName404, handler)
  }
  ErrNotLogin(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrNotLogin, handler)
  }
  NotFoundError(handler: Handler) {
    return this.inCodes(PropheticErrorCode.NotFoundError, handler)
  }
  ErrNoToken(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrNoToken, handler)
  }
  ErrPlayer404(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrPlayer404, handler)
  }
  ErrPlayerState404(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrPlayerState404, handler)
  }
  OK(handler: Handler) {
    return this.inCodes(PropheticErrorCode.OK, handler)
  }
  ErrCharacterData404(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrCharacterData404, handler)
  }
  ErrInvalidToken(handler: Handler) {
    return this.inCodes(PropheticErrorCode.ErrInvalidToken, handler)
  }
  AuthError(handler: Handler) {
    return this.inCodes(PropheticErrorCode.AuthError, handler)
  }
  handle() {
    return this.handler()
  }
}

const CODE_LESS_EXTENSION = { code: 'NONE' }
const findCodes = (error: ApolloError | GraphQLError): PropheticErrorCode[] => {
  if (error instanceof ApolloError) {
    return error.graphQLErrors.map(gError => findCodes(gError)[0])
  } else if (error.extensions) {
    const { extensions: { code } = CODE_LESS_EXTENSION } = error
    return [code]
  }

  return [PropheticErrorCode.CodeLessError]
}

export const errorHere = (error: ApolloError | GraphQLError | undefined) => {
  if (!error) {
    return new PropheticError([])
  }
  const codes = findCodes(error)
  return new PropheticError(codes)
}

export const isThis = (error: ApolloError | GraphQLError | undefined) => {
  if (!error) {
    return new PropheticErrorHandled([])
  }
  const codes = findCodes(error)
  return new PropheticErrorHandled(codes)
}
